[毎日Kotlin] Day39. The function apply
はじめに
毎日Kotlinシリーズです。
このシリーズを初めての方はこちらです。「毎日Kotlin」はじめました | Developers.IO
問題
The function apply | Try Kotlin
The previous examples can be rewritten using the library function apply (see examples below). Write your own implementation of this function named 'myApply'
fun <T> T.myApply(f: T.() -> Unit): T { TODO() } fun createString(): String { return StringBuilder().myApply { append("Numbers: ") for (i in 1..10) { append(i) } }.toString() } fun createMap(): Map<Int, String> { return hashMapOf<Int, String>().myApply { put(0, "0") for (i in 1..10) { put(i, "$i") } } }
狙い
ここで考えて欲しい問題の意図はなんだろうか?
スコープ関数を自作して仕組みを理解しよう。プチBuilderとして大活躍すること間違い無し。
解答例
fun <T> T.myApply(f: T.() -> Unit): T { f() return this }
これだけなんです。こういうちょっとしたコードが意外と便利だったりするんです。これでも十分なんですが、これだと関数呼び出し分遅くなってしまいます。
// 拡張関数を使わない、ベタな実装 fun createString(): String { val builder = StringBuilder() builder.append("Numbers: ") for (i in 1..10) { builder.append(i) } return builder.toString() } // 拡張関数つかった実装 // 関数呼び出し分遅い fun createString(): String { return StringBuilder().myApply { append("Numbers: ") for (i in 1..10) { append(i) } }.toString() } 文法が簡単になるかわりに速度を犠牲に。。。っと諦めようとしてるあなた!Kotlinなら**inline**という強い見方があります。単純にinlineを付けてあげます。 inline fun <T> T.myApply(f: T.() -> Unit): T { f() return this }
こうすると、ラムダ式の部分がコンパイル時に展開されて、コンパイル後は、以下と同じようなコードになっています。
fun createString(): String { val builder = StringBuilder() builder.append("Numbers: ") for (i in 1..10) { builder.append(i) } return builder.toString() }
おまけでJavaに戻した時のコード。
@NotNull public static final String createString() { Object $receiver$iv = new StringBuilder(); StringBuilder $receiver = $receiver$iv; $receiver$iv.append("Numbers: "); int i = 1; for(byte var3 = 10; i <= var3; ++i) { $receiver.append(i); } String var10000 = $receiver$iv.toString(); Intrinsics.checkExpressionValueIsNotNull(var10000, "StringBuilder().myApply … }\n }.toString()"); return var10000; }
あとがき
Day40.でまたお会いしましょう。